<?php


namespace App\Service;


use App\Model\Dao\ChannelCollectionMchConnDao;
use App\Model\Dao\ChannelInfoDao;
use App\Model\Dao\ChannelMchConnDao;
use App\Model\Dao\RiskRuleCollectionConnDao;
use App\Model\Dao\RiskRuleCollectionDao;
use App\Model\Dao\RiskRuleInfoDao;
use App\Model\Dao\RiskRuleMchRefDao;
use App\Model\Dao\RiskRuleWhitetextConnDao;
use App\Model\Enum\RiskRuleCollectionTypeEnum;
use App\Model\Enum\RiskRuleMchRefTypeEnum;
use App\Service\Dispatch\ChannelDispatchService;
use App\Service\RiskCheck\ChannelRiskCheckService;
use App\Service\RiskCheck\CommonRiskCheckService;
use App\Service\RiskCheck\GlobalRiskCheckService;
use App\Service\RiskCheck\MchRiskCheckService;
use App\Service\RiskCheck\MchWhiteRiskCheckService;
use App\Service\RiskCheck\SuspiciousRiskCheckService;
use App\Utils\CustomUtils;
use Hyperf\Database\Query\Builder;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Utils\ApplicationContext;

/**
 * Class SyncService
 *
 * @package App\Service
 */
class SyncService {

    /**
     * @var RiskRuleCollectionConnDao
     * @Inject()
     */
    protected $RiskRuleCollectionConnDao;

    /**
     * @var RiskRuleWhitetextConnDao
     * @Inject()
     */
    protected $RiskRuleWhitetextConnDao;

    /**
     * @var RiskRuleMchRefDao
     * @Inject()
     */
    protected $RiskRuleMchRefDao;

    /**
     * @var ChannelInfoDao
     * @Inject()
     */
    protected $ChannelInfoDao;

    /**
     * @var ChannelCollectionMchConnDao
     * @Inject()
     */
    protected $ChannelCollectionMchConnDao;

    /**
     * @var RiskRuleCollectionDao
     * @Inject()
     */
    protected $RiskRuleCollectionDao;

    /**
     * @var ChannelMchConnDao
     * @Inject()
     */
    protected $ChannelMchConnDao;

    /**
     * @var RiskRuleInfoDao
     * @Inject()
     */
    protected $RiskRuleInfoDao;

    /**
     * 当规则参数更新
     *
     * @param $paramId
     *
     * @return array
     */
    public function syncRiskRuleParam ($paramId) {

        var_dump('[缓存刷新] 规则参数: ', $paramId);

        ApplicationContext::getContainer()->get(CommonRiskCheckService::class)->clearCache($paramId);

        // 触发关联的规则明细更新
        $list = $this->RiskRuleInfoDao->getWhereList(['paramId' => $paramId]);
        foreach ($list as $item) {
            $this->syncRiskRuleInfo($item['id']);
        }

        return CustomUtils::buildSuccess();
    }

    /**
     * 当风控规则明细更新
     *
     * @param $ruleId
     *
     * @return array
     */
    public function syncRiskRuleInfo ($ruleId) {

        var_dump('[缓存刷新] 规则明细: ', $ruleId);

        // 当规则明细更新(risk_rule_info)->遍历受影响的规则集合->当风控规则集合更新

        // 获取关联的规则集合ID
        $list = $this->RiskRuleCollectionConnDao->getWhereList(['ruleId' => $ruleId]);

        // 遍历受影响的规则集合
        foreach ($list as $item) {

            // 当风控规则集合更新
            $this->syncRiskRuleCollection($item['collectionId']);
        }

        return CustomUtils::buildSuccess();
    }

    /**
     * 当风控规则集合更新
     *
     * @param $collectionId
     * @param $type
     *
     * @return array
     */
    public function syncRiskRuleCollection ($collectionId) {

        var_dump('[缓存刷新] 规则集合: ', $collectionId);

        // 当风控规则集合更新(risk_rule_collection)->遍历受影响的关联->更新(当全局风控关联更新/当商户风控关联更新/当通道风控关联更新/当商户可疑风控关联更新)

        $info = $this->RiskRuleCollectionDao->get($collectionId);

        if (!!$info) {
            $type = $info['type'];

            switch ($type) {
                case RiskRuleCollectionTypeEnum::GLOBAL:
                    $this->syncRuleGlobalRef();
                    break;

                case RiskRuleCollectionTypeEnum::MERCHANT:

                    $list = $this->RiskRuleMchRefDao->getWhereList([
                        'collectionId' => $collectionId,
                        'type'         => RiskRuleMchRefTypeEnum::NORMAL,
                    ]);

                    foreach ($list as $item) {
                        $this->syncRiskRuleMchRef($item['mchNo']);
                    }

                    break;

                case RiskRuleCollectionTypeEnum::CHANNEL:

                    $list = $this->ChannelInfoDao->getWhereList(['riskCollectionId' => $collectionId]);

                    foreach ($list as $item) {
                        $this->syncRiskRuleChannelRef($item['channelNo']);
                    }

                    break;

                case RiskRuleCollectionTypeEnum::SUSPICIOUS:

                    $list = $this->RiskRuleMchRefDao->getWhereList([
                        'collectionId' => $collectionId,
                        'type'         => RiskRuleMchRefTypeEnum::SUSPICIOUS,
                    ]);

                    foreach ($list as $item) {
                        $this->syncRiskRuleSuspiciousMchRef($item['mchNo']);
                    }

                    break;
            }
        }

        return CustomUtils::buildSuccess();
    }

    /**
     * 当商户白名单关联更新
     *
     * @param $mchNo
     *
     * @return array
     */
    public function syncRiskRuleWhiteTextMchRef ($mchNo) {

        var_dump('[缓存刷新] 商户白名单: ', $mchNo);

        // 刷新对应缓存
        ApplicationContext::getContainer()->get(MchWhiteRiskCheckService::class)->clearCache($mchNo);

        return CustomUtils::buildSuccess();
    }

    /**
     * 当商户风控关联更新
     *
     * @param $mchNo
     *
     * @return array
     */
    public function syncRiskRuleMchRef ($mchNo) {

        var_dump('[缓存刷新] 商户风控: ', $mchNo);

        // 刷新对应缓存
        ApplicationContext::getContainer()->get(MchRiskCheckService::class)->clearCache($mchNo);

        return CustomUtils::buildSuccess();
    }

    /**
     * 当商户可疑风控关联更新
     *
     * @param $mchNo
     *
     * @return array
     */
    public function syncRiskRuleSuspiciousMchRef ($mchNo) {

        var_dump('[缓存刷新] 商户可疑: ', $mchNo);

        // 刷新对应缓存
        ApplicationContext::getContainer()->get(SuspiciousRiskCheckService::class)->clearCache($mchNo);

        return CustomUtils::buildSuccess();
    }

    /**
     * 当白名单参数更新
     *
     * @param $paramId
     *
     * @return array
     */
    public function syncWhiteTextParam ($paramId) {

        var_dump('[缓存刷新] 白名单参数: ', $paramId);

        // 查询关联的白名单ID
        $whiteTextList = $this->RiskRuleWhitetextConnDao->getWhereList(['paramId' => $paramId]);

        // 遍历触发白名单集合更新
        foreach ($whiteTextList as $item) {
            $this->syncWhiteText($item['whiteTextId']);
        }

        return CustomUtils::buildSuccess();
    }

    /**
     * 当通道/通道集合更新
     *
     * @param $conn
     *
     * @return array
     */
    public function syncChannelCollection ($conn) {

        var_dump('[缓存刷新] 通道/通道集合: ', $conn);

        $ChannelDispatchService = ApplicationContext::getContainer()->get(ChannelDispatchService::class);

        // 当通道/通道集合更新->清通道缓存->遍历受影响商户通道->清缓存

        $channelNoList = array_column($conn, 'channelNo');

        // 通道风控清空
        foreach ($channelNoList as $channelNo) {
            $this->syncRiskRuleChannelRef($channelNo);
        }

        // 通道缓存清空
        foreach ($channelNoList as $channelNo) {
            $ChannelDispatchService->clearChannel($channelNo);
        }

        // 商户-通道缓存清空
        if (!empty($channelNoList)) {

            // 获取关联商户
            $conn = $this->ChannelMchConnDao->getWhereList(function (Builder $query) use ($channelNoList) {
                $query->whereIn('channelNo', $channelNoList);
            });

            $mchNoList = array_column($conn, 'mchNo');

            foreach ($mchNoList as $mchNo) {

                // 当商户-通道关联集合更新
                $this->syncChannelCollectionMchRef($mchNo);
            }
        }


        return CustomUtils::buildSuccess();
    }

    /**
     * 当白名单集合更新
     *
     * @param $collectionId
     *
     * @return array
     */
    public function syncWhiteText ($collectionId) {

        var_dump('[缓存刷新] 白名单集合: ', $collectionId);

        // 查询关联商户
        $list = $this->RiskRuleMchRefDao->getWhereList([
            'collectionId' => $collectionId,
            'type'         => RiskRuleMchRefTypeEnum::WHITE,
        ]);

        // 遍历触发商户白名单关联更新
        foreach ($list as $item) {
            $this->syncRiskRuleWhiteTextMchRef($item['mchNo']);
        }

        return CustomUtils::buildSuccess();
    }

    /**
     * 当商户关联通道集合更新
     *
     * @param $mchNo
     *
     * @return array
     */
    public function syncChannelCollectionMchRef ($mchNo) {

        var_dump('[缓存刷新] 商户通道: ', $mchNo);

        // 当商户关联通道集合更新
        ApplicationContext::getContainer()->get(ChannelDispatchService::class)->clearMchChannelCache($mchNo);

        return CustomUtils::buildSuccess();
    }

    /**
     * 当通道风控关联更新
     *
     * @param $channelNo
     *
     * @return array
     */
    public function syncRiskRuleChannelRef ($channelNo) {

        var_dump('[缓存刷新] 通道风控: ', $channelNo);

        // 刷新对应缓存
        ApplicationContext::getContainer()->get(ChannelRiskCheckService::class)->clearCache($channelNo);

        return CustomUtils::buildSuccess();
    }

    /**
     * 当全局风控关联更新
     *
     * @return array
     */
    public function syncRuleGlobalRef () {

        var_dump('[缓存刷新] 全局风控');

        // 刷新对应缓存
        ApplicationContext::getContainer()->get(GlobalRiskCheckService::class)->clearCache();

        return CustomUtils::buildSuccess();
    }

    /**
     * 开启/关闭通道
     *
     * @param $mchNo
     * @param $channelNo
     * @param $status
     *
     * @return array
     */
    public function setMchChannelStatus ($mchNo, $channelNo, $status) {
        return ApplicationContext::getContainer()->get(ChannelDispatchService::class)->setMchChannelStatus($mchNo, $channelNo, $status);
    }

    /**
     * 获取通道限额消耗
     *
     * @param $channelNo
     *
     * @return array
     */
    public function getChannelCost ($channelNo) {
        return ApplicationContext::getContainer()->get(ChannelDispatchService::class)->getChannelCost($channelNo);
    }

    /**
     * 获取商户-通道限额消耗
     * @param $mchNo
     * @param $channelNo
     *
     * @return array
     */
    public function getMchChannelCost ($mchNo, $channelNo) {
        return ApplicationContext::getContainer()->get(ChannelDispatchService::class)->getMchChannelCost($mchNo, $channelNo);
    }

    /**
     * 额度回滚操作
     *
     * @param $params
     *
     * @return array
     */
    public function rollbackChannelLimit ($params) {

        $mchNo     = $params['mchNo'];
        $channelNo = $params['channelNo'];
        $amount    = $params['channelLimitAmount'];
        $year      = $params['year'];
        $month     = $params['month'];
        $day       = $params['day'];

        // 更新额度:商户侧/通道侧,日周期/月周期,次数/金额, 只处理当天和当月的情况

        if ($year.$month == date('Ym')) {
            $this->ChannelInfoDao->incrChannelLimitCost($mchNo, $channelNo, intval(-1 * $amount), -1, 'month');
        }

        if ($year.$month.$day == date('Ymd')) {
            $this->ChannelInfoDao->incrChannelLimitCost($mchNo, $channelNo, intval(-1 * $amount), -1, 'day');
        }

        // 刷新对应通道/商户-通道的缓存
        $this->syncChannelCollection([['channelNo' => $channelNo]]);

        return CustomUtils::buildSuccess();
    }


}
